<?php
/**
 * Created by PhpStorm.
 * User: shaowei
 * Date: 2019/5/9
 * Time: 下午3:48
 */

namespace App\Http\Services;


use App\Http\Model\Hint;
use App\Http\Model\User;
use App\Http\Model\UserReverify;
use App\Http\Model\UserVerify;
use App\Lib\faceid;
use App\Lib\faceTencent;
use App\Lib\Publisher;
use Exception;
use App\Http\Services\UserServices;

class UserVerifyServices extends CommonServices
{
    private $model_user_verify;
    private $user_verify_count = 5; // 定义用户验证上限次数
    private $user_service;

    /**
     * 礼物服务
     *
     * @var GiftServices
     */
    private $giftService;

    public function __construct(){
        $this->user = new User();
        $this->model_user_verify = new UserVerify();
        $this->giftService = new GiftServices();
        $this->user_service = new UserServices();
    }

    public function getToken($idcardName, $idcardNumber){
        //未成年
        $baby = $this->model_user_verify->isMan($idcardNumber);
        if(!$baby) {
            return Hint::JUVENILES_NOT_VERIFY;
        }

        $user = $this->user->get_current_user();
        if (empty($user)){
            return Hint::LOGIN_OUT;
        }
        $userId = $user['user_id'];
        if ($user['active_certify'] == 1){
            return Hint::USER_VERIFY_EXIST;
        }
        if ($this->model_user_verify->getSuccess($userId)) {
            return Hint::USER_VERIFY_EXIST;
        }
        $count = $this->model_user_verify->getCount($userId);
        if ($count >= $this->user_verify_count){
            return Hint::USER_VERIFY_BEYOND;
        }

        $idcardCount = $this->model_user_verify->getIdcardCount($idcardNumber);
        if ($idcardCount >= 5){
            return Hint::USER_VERIFY_IDCARD_EXCEEDING;
        }

        $faceid = new faceid();
        $bizNo = time().rand(100000, 999999);
        $token = $faceid->getToken($idcardName, $idcardNumber, $bizNo);
        if (empty($token)){
            return Hint::USER_VERIFY_ID_NUMBER_NAME_NOT_MATCH;
        }
        $this->model_user_verify->add($userId,$token, $bizNo, $idcardName, $idcardNumber);
        return $token;
    }

    public function getFaceSign($idcardName, $idcardNumber){
        //未成年
        $baby = $this->model_user_verify->isMan($idcardNumber);
        if(!$baby) {
            return Hint::JUVENILES_NOT_VERIFY;
        }

        $user = $this->user->get_current_user();
        if (empty($user)){
            return Hint::LOGIN_OUT;
        }

        $userId = $user['user_id'];
        if ($user['active_certify'] == 1){
            return Hint::USER_VERIFY_EXIST;
        }
        if ($this->model_user_verify->getSuccess($userId)) {
            return Hint::USER_VERIFY_EXIST;
        }
        $count = $this->model_user_verify->getCount($userId);
        if ($count >= $this->user_verify_count){
            return Hint::USER_VERIFY_BEYOND;
        }

        $idcardCount = $this->model_user_verify->getIdcardCount($idcardNumber);
        if ($idcardCount >= 5){
            return Hint::USER_VERIFY_IDCARD_EXCEEDING;
        }

        $face = new faceTencent();
        $orderNo = $face->getOrderNo();
        $nonce = $face->random();
        $frontSign = $face->getFrontSign($userId, $nonce);
        if (empty($frontSign)) {
            return Hint::USER_VERIFY_SIGN_EMPTY;
        }

        $faceId = $face->getFaceId($userId, $idcardName, $idcardNumber, $orderNo, $nonce);
        if (is_numeric($faceId)) {
            return $faceId;
        }

        $this->model_user_verify->add($userId, $frontSign, $orderNo, $idcardName, $idcardNumber);

        $ret = [
            'user_id' => $userId,
            'nonce' => $nonce,
            'sign' => $frontSign,
            'orderNo' => $orderNo,
            'faceId' => $faceId,
        ];
        return $ret;
    }

    public function reverifyResult($sign){
        $user = $this->user->get_current_user();
        if (empty($user)){
            return Hint::LOGIN_OUT;
        }
//        $userId = 888;
        $userId = $user['user_id'];
	$item = $this->model_user_verify->get($userId, $sign);
	write_log("user-verify", "reverifyResult", ['$userId' => $userId, '$sign' => $sign, '$item' => $item]);
        if (empty($item)){
            return Hint::USER_VERIFY_NOT_FIND;
        }

        if (!empty($item->result_code)){
            //return Hint::USER_VERIFY_SIGN_EXP;
        }

        $face = new faceTencent();
        $nonce = $face->random();
        $res = $face->verify($item->biz_no, $nonce);
        if ($res['code'] != 0) {
            // fail
            $resultCode = $res['code'];
            $resultMessage = $res['msg'];
        } else {
            $resultCode = 1000;
            $resultMessage = $res['msg'];
        }

        $this->model_user_verify->setResult($item->token, $resultCode, $resultMessage);
        if (intval($resultCode) == 1000){
            $this->user->set_certify($userId);

            //MQ通知
            $publishObject = Publisher::getInstance();
            $publishObject->requestData = [
                'queue_route' => 'global.user.verify',
                'data' => [
                    'user_id' => $userId,// 用户ID
                    'time' => time()
                ],
            ];
            $publishObject->publisher();

            return Hint::SUCCESS;
        }

        return Hint::ERROR;
    }

    public function getReveiryToken($idcardName, $idcardNumber){
        $user = $this->user->get_current_user();
        if (empty($user)){
            return Hint::LOGIN_OUT;
        }
        $userId = $user['user_id'];
        $verifyInfo = $this->model_user_verify->getSuccess($userId);
        //如果还没有认证则返回匹配错误
        if ($verifyInfo == null
            || strtolower($idcardName) != $verifyInfo['idcard_name']
            || $idcardNumber != $verifyInfo['idcard_number'] ) {
            return Hint::USER_VERIFY_ID_NUMBER_NAME_NOT_MATCH;
        }

        $faceid = new faceid();
        $bizNo = time().rand(100000, 999999);
        $token = $faceid->getToken($idcardName, $idcardNumber, $bizNo);
        if (empty($token)){
            return Hint::USER_VERIFY_ID_NUMBER_NAME_NOT_MATCH;
        }
        $ua = $this->parse_app_UA();
        $guid = $ua['guid']??'';
        (new UserReverify())->add($userId,$token, $bizNo, $idcardName, $idcardNumber, $guid);
        return $token;
    }

    /*
         * 获取用户验证次数
         * */
    public function getUserCount()
    {
        $user = $this->user->get_current_user();
        if (empty($user)){
            return Hint::LOGIN_OUT;
        }
        $userId = $user['user_id'];
        $count =  $this->user_verify_count  -  $this->model_user_verify->getCount($userId);
        if($count < 0 ){
            $count = 0;
        }
        return $count;
    }

    public function complete($token, $dataPath){
        $user = $this->user->get_current_user();
        if (empty($user)){
            return Hint::LOGIN_OUT;
        }
        $userId = $user['user_id'];
        $item = $this->model_user_verify->get($userId, $token);
        if (empty($item)){
            return Hint::USER_VERIFY_NOT_FIND;
        }
        if (!empty($item->result_code)){
            return Hint::USER_VERIFY_NOT_FIND;
        }
        $count = $this->model_user_verify->getCount($userId);
        if ($count >= $this->user_verify_count){
            return Hint::USER_VERIFY_BEYOND;
        }
        $faceid = new faceid();
        $data = $faceid->verify($token, $dataPath);
        if (empty($data)){
            return Hint::USER_VERIFY_FAILED;
        }
        $resultCode = $data['result_code'];
        $resultMessage = $data['result_message'];
        $this->model_user_verify->setResult($token, $resultCode, $resultMessage);
        if (intval($resultCode) == 1000){
            $this->user->set_certify($userId);

            //MQ通知
            $publishObject = Publisher::getInstance();
            $publishObject->requestData = [
                'queue_route' => 'global.user.verify',
                'data' => [
                    'user_id' => $userId,// 用户ID
                    'time' => time()
                ],
            ];
            $publishObject->publisher();

            return Hint::SUCCESS;
        }
        if ($resultMessage == 'PASS_LIVING_NOT_THE_SAME'){
            return Hint::USER_VERIFY_PASS_LIVING_NOT_THE_SAME;
        }
        if ($resultMessage == 'NO_ID_CARD_NUMBER'){
            return Hint::USER_VERIFY_NO_ID_CARD_NUMBER;
        }
        if ($resultMessage == 'ID_NUMBER_NAME_NOT_MATCH'){
            return Hint::USER_VERIFY_ID_NUMBER_NAME_NOT_MATCH;
        }
        if ($resultMessage == 'NO_FACE_FOUND'){
            return Hint::USER_VERIFY_NO_FACE_FOUND;
        }
        if ($resultMessage == 'NO_ID_PHOTO'){
            return Hint::USER_VERIFY_NO_ID_PHOTO;
        }
        if ($resultMessage == 'PHOTO_FORMAT_ERROR'){
            return Hint::USER_VERIFY_PHOTO_FORMAT_ERROR;
        }
        if ($resultMessage == 'DATA_SOURCE_ERROR'){
            return Hint::USER_VERIFY_DATA_SOURCE_ERROR;
        }
        if ($resultMessage == 'FAIL_LIVING_FACE_ATTACK'){
            return Hint::USER_VERIFY_FAIL_LIVING_FACE_ATTACK;
        }
        if ($resultMessage == 'VIDEO_LACK_FRAMES'){
            return Hint::USER_VERIFY_VIDEO_LACK_FRAMES;
        }
        if ($resultMessage == 'FAIL_EYES_CLOSE_DETECTION'){
            return Hint::USER_VERIFY_FAIL_EYES_CLOSE_DETECTION;
        }
        if ($resultMessage == 'BIZ_TOKEN_DENIED'){
            return Hint::USER_VERIFY_BIZ_TOKEN_DENIED;
        }
        if ($resultMessage == 'AUTHENTICATION_FAIL'){
            return Hint::USER_VERIFY_AUTHENTICATION_FAIL;
        }
        if ($resultMessage == 'MOBILE_PHONE_NOT_SUPPORT'){
            return Hint::USER_VERIFY_MOBILE_PHONE_NOT_SUPPORT;
        }
        if ($resultMessage == 'SDK_TOO_OLD'){
            return Hint::USER_VERIFY_SDK_TOO_OLD;
        }
        if ($resultMessage == 'MOBILE_PHONE_NO_AUTHORITY'){
            return Hint::USER_VERIFY_MOBILE_PHONE_NO_AUTHORITY;
        }
        if ($resultMessage == 'USER_CANCELLATION'){
            return Hint::USER_VERIFY_USER_CANCELLATION;
        }
        if ($resultMessage == 'USER_TIMEOUT'){
            return Hint::USER_VERIFY_USER_TIMEOUT;
        }
        if ($resultMessage == 'VERIFICATION_FAILURE'){
            return Hint::USER_VERIFY_VERIFICATION_FAILURE;
        }
        if ($resultMessage == 'UNDETECTED_FACE'){
            return Hint::USER_VERIFY_UNDETECTED_FACE;
        }
        if ($resultMessage == 'ACTION_ERROR'){
            return Hint::USER_VERIFY_ACTION_ERROR;
        }
        return Hint::ERROR;
    }

    public function reverifyComplete($token, $dataPath){
        $user = $this->user->get_current_user();
        if (empty($user)){
            return Hint::LOGIN_OUT;
        }
        $userId = $user['user_id'];
        $userReverifyModel = new UserReverify();
        $item = $userReverifyModel->get($userId, $token);
        if (empty($item)){
            return Hint::USER_VERIFY_NOT_FIND;
        }
        if (!empty($item->result_code)){
            return Hint::USER_VERIFY_NOT_FIND;
        }

        $faceid = new faceid();
        $data = $faceid->verify($token, $dataPath);
        if (empty($data)){
            return Hint::USER_VERIFY_FAILED;
        }
        $resultCode = $data['result_code'];
        $resultMessage = $data['result_message'];
        $userReverifyModel->setResult($token, $resultCode, $resultMessage);
        if (intval($resultCode) == 1000){
            
            //MQ通知
            $publishObject = Publisher::getInstance();
            $publishObject->requestData = [
                'queue_route' => 'global.user.verify',
                'data' => [
                    'user_id' => $userId,// 用户ID
                    'time' => time()
                ],
            ];
            $publishObject->publisher();

            return Hint::SUCCESS;
        }
        if ($resultMessage == 'PASS_LIVING_NOT_THE_SAME'){
            return Hint::USER_VERIFY_PASS_LIVING_NOT_THE_SAME;
        }
        if ($resultMessage == 'NO_ID_CARD_NUMBER'){
            return Hint::USER_VERIFY_NO_ID_CARD_NUMBER;
        }
        if ($resultMessage == 'ID_NUMBER_NAME_NOT_MATCH'){
            return Hint::USER_VERIFY_ID_NUMBER_NAME_NOT_MATCH;
        }
        if ($resultMessage == 'NO_FACE_FOUND'){
            return Hint::USER_VERIFY_NO_FACE_FOUND;
        }
        if ($resultMessage == 'NO_ID_PHOTO'){
            return Hint::USER_VERIFY_NO_ID_PHOTO;
        }
        if ($resultMessage == 'PHOTO_FORMAT_ERROR'){
            return Hint::USER_VERIFY_PHOTO_FORMAT_ERROR;
        }
        if ($resultMessage == 'DATA_SOURCE_ERROR'){
            return Hint::USER_VERIFY_DATA_SOURCE_ERROR;
        }
        if ($resultMessage == 'FAIL_LIVING_FACE_ATTACK'){
            return Hint::USER_VERIFY_FAIL_LIVING_FACE_ATTACK;
        }
        if ($resultMessage == 'VIDEO_LACK_FRAMES'){
            return Hint::USER_VERIFY_VIDEO_LACK_FRAMES;
        }
        if ($resultMessage == 'FAIL_EYES_CLOSE_DETECTION'){
            return Hint::USER_VERIFY_FAIL_EYES_CLOSE_DETECTION;
        }
        if ($resultMessage == 'BIZ_TOKEN_DENIED'){
            return Hint::USER_VERIFY_BIZ_TOKEN_DENIED;
        }
        if ($resultMessage == 'AUTHENTICATION_FAIL'){
            return Hint::USER_VERIFY_AUTHENTICATION_FAIL;
        }
        if ($resultMessage == 'MOBILE_PHONE_NOT_SUPPORT'){
            return Hint::USER_VERIFY_MOBILE_PHONE_NOT_SUPPORT;
        }
        if ($resultMessage == 'SDK_TOO_OLD'){
            return Hint::USER_VERIFY_SDK_TOO_OLD;
        }
        if ($resultMessage == 'MOBILE_PHONE_NO_AUTHORITY'){
            return Hint::USER_VERIFY_MOBILE_PHONE_NO_AUTHORITY;
        }
        if ($resultMessage == 'USER_CANCELLATION'){
            return Hint::USER_VERIFY_USER_CANCELLATION;
        }
        if ($resultMessage == 'USER_TIMEOUT'){
            return Hint::USER_VERIFY_USER_TIMEOUT;
        }
        if ($resultMessage == 'VERIFICATION_FAILURE'){
            return Hint::USER_VERIFY_VERIFICATION_FAILURE;
        }
        if ($resultMessage == 'UNDETECTED_FACE'){
            return Hint::USER_VERIFY_UNDETECTED_FACE;
        }
        if ($resultMessage == 'ACTION_ERROR'){
            return Hint::USER_VERIFY_ACTION_ERROR;
        }
        return Hint::ERROR;
    }

    public function getInfo(){
        $user = $this->user->get_current_user();
        if (empty($user)){
            return Hint::LOGIN_OUT;
        }
        $userId = $user['user_id'];

        $successInfo = $this->model_user_verify->getSuccess($userId);
        if (empty($successInfo)){
            return Hint::USER_VERIFY_NOT_ACTION;
        }
        return ['idcard_name'=>hide_string($successInfo['idcard_name'], 0, 1), 'idcard_number'=>hide_string($successInfo['idcard_number'],3, 4)];
    }

    public function getInfoByUser($params=[]){
        init_redis_session();

        $code = Hint::SUCCESS;
        $data = [];

        do {
            $userId = $_SESSION['user_id'] ?? 0;
            if (empty($userId)) {
                $code = Hint::LOGIN_OUT;
                break;
            }
            $params['user_id'] = $userId;

            if(empty($params['idcard_number'] ?? '')){
                $code = Hint::PARAM_ERROR;
                break;
            }

            $data = $this->model_user_verify->getInfoByUser($params);
            if(empty($data)){
                $code = Hint::USER_VERIFY_ID_NUMBER_NAME_NOT_MATCH;
                break;
            }

        }while(false);

        return compact('code','data');
    }

    /*
     * 添加用户验证
     * @param [$user_id]   用户id
     * @param [$userName]   用户姓名
     * @param [$idNumber]   用户身份证号
     * @param [$type]   cms type类型    0 移动端   1 cms
     * */
    public function create_user_verify($user_id,$idcardName,$idNumber)
    {
        $user_info = $this->user->get_user($user_id);
        if (empty($user_info)) {
            return Hint::ERROR;
        }
        $token = time().getRoundToken();
        $bizNo = time().rand(100000, 999999);
        $res = $this->model_user_verify->cmsAdd($user_id,$token, $bizNo, $idcardName, $idNumber);
        if(!$res){
            return Hint::ERROR;
        }
        return Hint::SUCCESS;
    }
    public function clearVerify($user_id){
        return $this->model_user_verify->clearVerify($user_id);
    }

    /**
     * 用户消费前验证
     *
     * @param $toUserIds
     * @return void
     */
    public function userConsumptionVerify($toUserIds)
    {
        $user = $this->user->get_current_user();
        if (empty($user)){
            return Hint::LOGIN_OUT;
        }
        $userStatus = (new UserVerify())->isAdult($user['user_id']);
        //未成年：土司提示-为呵护未成年人健康成长，未成年人不允许充值（未满18岁）
        if ($userStatus == 0) {
            throw new Exception(Hint::$Msg[Hint::JUVENILES_NOT_REWARD], Hint::JUVENILES_NOT_REWARD);
        }
        //未认证用户无法消费哦，请前往实名认证
        if ($userStatus == -1) {
            throw new Exception(Hint::$Msg[Hint::ROOM_GIFT__USER_NOT_VERIFY], Hint::ROOM_GIFT__USER_NOT_VERIFY);
        }
        //检测被赠送人是否账号异常
        $checkAbnormalUserResult = $this->giftService->checkAbnormalUser($toUserIds);
        if ($checkAbnormalUserResult['code'] != Hint::SUCCESS) {
            throw new Exception($checkAbnormalUserResult['msg'], $checkAbnormalUserResult['code']);
        }

        return true;
    }

    public static function isAdult(int $userId) {
        $res = (new UserVerify())->isAdult($userId);
        return (int) $res;
    }

    /**
     * 清理用户实名认证
     */
    public function clearUserAll($userId)
    {
        //数据删除
        $this->model_user_verify->deleteByUserId($userId);
        //认证状态
        $this->user_service->cms_set_certify($userId, 0);

        return true;
    }

}
